import {Body, Controller, Get, HttpStatus, Post, Query, Res, Headers} from '@nestjs/common';
import {Response} from 'express';
import {TencentService} from '../service/tencent.service';
import {CommonRedisService} from '../service/common.redis.service';
import {RecordListService} from '../service/record.list.service';
import {UserListService} from '../service/user.list.service';
import {CommonResponseDto} from '../dto/common.response.dto';
import {ResCode, UserStatus} from '../common/constants';
import AppConfig from 'config/app.config';
import {formatTimeToDateStr, uuid} from "../common/utils";
import {decrypt, getModelPrice, setErrorStreamRes} from "../common/common";
import Decimal from "decimal.js";

const platform = 'tencent'

@Controller('stream/' + platform)
export class TencentController {
    constructor(private readonly commonRedisService: CommonRedisService, private readonly tencentService: TencentService,
                private readonly recordListService: RecordListService, private readonly userListService: UserListService) {}

    @Post('/chat')
    async chat(@Headers() headers: Record<string, string>, @Body() params: {content: string, model: string }, @Res({ passthrough: false }) res: Response) {
        console.log(params)
        const modelConfig = AppConfig.ModelConfig[platform]
        if (!params.model) {
            params.model = modelConfig.dsr1.code
        }
        if (![modelConfig.dsr1.code, modelConfig.dsv3.code].includes(params.model)) {
            params.model = modelConfig.dsr1.code
        }
        const model = modelConfig[params.model].model
        const modelPrice = getModelPrice(platform, params.model)
        res.setHeader('Content-Type', 'text/event-stream; charset=utf-8');
        res.setHeader('Cache-Control', 'no-cache');
        res.setHeader('Connection', 'keep-alive');
        res.status(HttpStatus.OK);
        const headerToken = headers['api-token'] || headers['Api-Token'] || headers['ApiToken'] || headers['apiToken'] || headers['apitoken'] || ''
        if (!params.content || !headerToken) {
            setErrorStreamRes('参数缺失', res)
        } else {
            try {
                const decryptStr = decrypt(headerToken, AppConfig.ApiTokenSecretKey)
                const strArr = decryptStr.split('_')
                if (strArr.length !== 2) {
                    setErrorStreamRes('api-token非法', res)
                } else {
                    const userId: string = strArr[0]
                    const token = await this.commonRedisService.get(AppConfig.ApiHeaderKey + '_' + userId)
                    if (!token || token !== headerToken) {
                        setErrorStreamRes('非法用户', res)
                    } else {
                        const user = await this.userListService.getOneById(userId)
                        if (!user) {
                            setErrorStreamRes('用户不存在', res)
                        } else if(user.status !== UserStatus.NORMAL){
                            setErrorStreamRes('用户状态异常', res)
                        } else if(new Decimal(user.balance).lessThanOrEqualTo(0.1)){
                            setErrorStreamRes('余额不足0.1', res)
                        } else {
                            const useage = {
                                outTokens: 0,
                                inTokens: 0,
                                totalTokens: 0,
                            }
                            this.tencentService.chatComp(params.content, model, async (msg) => {
                                const data = msg.data
                                // console.log('message data', data)
                                if (data === '[DONE]') {
                                    console.log('本次回答计量：' + JSON.stringify(useage))
                                    const date = formatTimeToDateStr(new Date().getTime())
                                    this.recordListService.createUpdateOne({
                                        id: uuid(32),
                                        userId: userId,
                                        date,
                                        inToken: Number(useage.inTokens),
                                        outToken: Number(useage.outTokens),
                                        totalToken: Number(useage.totalTokens),
                                        model: `${platform}[#]${params.model}`,
                                        inPrice: '',
                                        outPrice: ''
                                    }, modelPrice)
                                    res.end('[DONE]')
                                } else {
                                    try {
                                        const dataObj = JSON.parse(data)
                                        useage.outTokens = dataObj.Usage.CompletionTokens
                                        useage.inTokens = dataObj.Usage.PromptTokens
                                        useage.totalTokens = dataObj.Usage.TotalTokens
                                        const choices = JSON.parse(data).Choices
                                        if (choices.length > 1) {
                                            choices.sort((a, b) => {
                                                return a.Index-b.Index
                                            })
                                        }
                                        let obj: any = {
                                            id: dataObj.Id
                                        }
                                        choices.forEach((choice) => {
                                            const delta = choice.Delta
                                            if (delta.hasOwnProperty('ReasoningContent')) {
                                                if (!obj.reasoning) {
                                                    obj.reasoning = ''
                                                }
                                                obj.reasoning += delta.ReasoningContent
                                            } else if (delta.hasOwnProperty('Content')) {
                                                if (!obj.answer) {
                                                    obj.answer = ''
                                                }
                                                obj.answer += delta.Content
                                            }
                                        })
                                        res.write('data: '+JSON.stringify(obj)+'\n\n')
                                    } catch(e){
                                        console.log(e)
                                    }
                                }
                            }, () => {
                                res.end('')
                            })
                        }
                    }
                }
            } catch(e){
                setErrorStreamRes('服务异常', res)
            }
        }
    }
}
